package fr.ing4.Macri.MonteCarlo.SingleThread;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;

import fr.ing4.Macri.MonteCarlo.GUI.MyFrame;

/**
 * 
 */

/**
 * @author enzo
 * 
 */
public class MonteCarloSimulation extends Observable implements Runnable {
	
	private Observer viewToUpdate;
	private String callPutFlag;
	private double s, x, r, t, b, v;
	private int nSteps, nSimu;
	private double res, time;
	boolean finish=false;
	public double progress;
	
	/**
	 * @return the res
	 */
	

	public MonteCarloSimulation(Observer view)
	{
		this.viewToUpdate=view;
	}

	public double MonteCarloStandardOption() {
		double dt, st;
		double sum = 0, drift, vSqrdt;
		int i, j, z = 0;
		Random random = new Random();

		dt = this.t / this.nSteps;
		drift = (this.b - this.v * this.v / 2) * dt;
		vSqrdt = this.v * Math.sqrt(dt);
		if (this.callPutFlag.contentEquals("c"))
			z = 1;
		else if (this.callPutFlag.contentEquals("p"))
			z = -1;
		for (i = 1; i <= this.nSimu; i++) {
			st = this.s;
			for (j = 1; j <= this.nSteps; j++) {
				st = st * Math.exp(drift + vSqrdt * random.nextGaussian());
			}
			sum = sum + Math.max(z * (st - this.x), 0);
			progress=i*100/this.nSimu;
			 setChanged();
			 notifyObservers(this);
		}
		
		System.out.println("res:"+Math.exp(-this.r * this.t) * (sum / this.nSimu));
		return Math.exp(-this.r * this.t) * (sum / this.nSimu);
		
	}
	
	public void setValues(String callPutFlag,double s,double x,double t,double r,double b,double v,int nSteps,int nSimu)
	{
		this.callPutFlag=callPutFlag;
		this.s=s;
		this.x=x;
		this.t=t;
		this.r=r;
		this.b=b;
		this.v=v;
		this.nSteps=nSteps;
		this.nSimu=nSimu;
		this.finish=false;
	}

	@Override
	public void run() {
		long time1=System.currentTimeMillis();
		this.res=this.MonteCarloStandardOption();
		this.finish=true;
		long time2= System.currentTimeMillis();
	    this.time=time2-time1;
	    setChanged();
		notifyObservers(this);
		
	}
	
	
	/**
	 * @param args
	 */
	
	public double getRes() {
		return res;
	}

	/**
	 * @return the time
	 */
	public double getTime() {
		return time;
	}

	/**
	 * @return the finish
	 */
	public boolean isFinish() {
		return finish;
	}
}
